package xyz.hubery.task;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.retry.annotation.Retryable;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MimeTypeUtils;
import xyz.hubery.domain.AsyncTask;
import xyz.hubery.domain.EntrustOrder;
import xyz.hubery.dto.FreezeDTO;
import xyz.hubery.enums.AsyncTaskStatus;
import xyz.hubery.enums.AsyncTaskType;
import xyz.hubery.enums.OrderStatus;
import xyz.hubery.feign.AccountServiceFeign;
import xyz.hubery.handler.AsyncTaskHandler;
import xyz.hubery.mapper.AsyncTaskMapper;
import xyz.hubery.mapper.EntrustOrderMapper;
import xyz.hubery.model.Constant;
import xyz.hubery.model.R;
import xyz.hubery.model.TaskResult;
import xyz.hubery.stream.Source;

import java.io.Serializable;

/**
 * 解冻资金处理器：
 */
@Component
@Slf4j
public class UnfreezeBalanceHandler implements AsyncTaskHandler {

    @Autowired
    private AccountServiceFeign accountServiceFeign;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private AsyncTaskMapper asyncTaskMapper;
    @Autowired
    private EntrustOrderMapper entrustOrderMapper;
    @Autowired
    private Source source;

    @Override
    public AsyncTaskType getSupportedType() {
        return AsyncTaskType.UNFREEZE_BALANCE;
    }

    //    @Retryable(value = Exception.class, maxAttempts = Constant.TASK_MAX_RETRY)
    @Transactional
    @Override
    public TaskResult handle(AsyncTask task) {
        // 幂等操作，防止同一多次操作
        if (Boolean.TRUE.equals(redisTemplate.hasKey(getSupportedType() + ":" + task.getId()))) {
            return TaskResult.success();
        }
        FreezeDTO dto = JSON.parseObject(task.getPayload(), FreezeDTO.class);

        // 调用资金服务解冻
        R result = accountServiceFeign.unFreeze(dto);

        if (result.getCode() == R.ok().getCode()) { // 远程调用成功
            // 添加到缓存
            redisTemplate.opsForValue().set(getSupportedType() + ":" + task.getId(), "");
            return TaskResult.success(dto.getOrderId()); // 用于更新订单状态
        } else { //调用失败
            return TaskResult.retry("解冻失败，稍后重试");
        }
    }


    @Transactional
    @Override
    public void onSuccess(AsyncTask task, TaskResult result) {
        // 设置委托单状态为取消、任务状态为成功
        int i = entrustOrderMapper.updateStatus((Long) result.getData(), OrderStatus.CANCELED.getCode());
        int j = asyncTaskMapper.updateStatus(task.getId(), task.getVersion(), AsyncTaskStatus.SUCCESS.getCode());

        if (i <= 0 || j <= 0) { // 操作失败，需要重试
            task.setMsg("委托单更新失败或异步任务更新失败" );
            this.onRetry(task);
        }

        EntrustOrder entrustOrder = entrustOrderMapper.selectById((Serializable) result.getData());
        if (i > 0 && j > 0) { // 操作成功
            // 发送消息到消息队列（告知撮合服务删除该订单）
            MessageBuilder<EntrustOrder> builder = MessageBuilder.withPayload(entrustOrder).setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
            source.remOrderOut().send(builder.build());
        }
    }

    @Transactional
    @Override
    public void onFailure(AsyncTask task, TaskResult result) {
        // 重试次数+1，设置错误消息，
        task.setMsg(result.getMessage());
        task.setRetryCount(task.getRetryCount() + 1);
        asyncTaskMapper.failUpdate(task);
        // 重试
        this.onRetry(task);
    }

    @Override
    public void onRetry(AsyncTask task) {
        throw new RuntimeException("异步任务处理失败:"+task.getId() );
    }

    @Override
    public void onSkipped(AsyncTask task, String reason) {
        AsyncTaskHandler.super.onSkipped(task, reason);
    }
}